const commands = require('commands');
const TextEncoder = require('bluetooth-printer/index').TextEncoder;

const printerJobs = function () {
    this._queue = Array.from(commands.HARDWARE.HW_INIT);
    this._encoder = new TextEncoder("gb2312", {
        NONSTANDARD_allowLegacyEncoding: true
    });
    this.
    _enqueue = function (cmd) {
        this._queue.push.apply(this._queue, cmd);
    }
};


/**
 * 增加打印内容
 * @param  {string} content  文字内容
 */
printerJobs.prototype.text = function (content) {
    if (content) {
        let uint8Array = this._encoder.encode(content);
        let encoded = Array.from(uint8Array);
        this._enqueue(encoded);
    }
    return this;
};

/**
 * 打印文字
 * @param  {string} content  文字内容
 */
printerJobs.prototype.print = function (content) {
    this.text(content);
    this._enqueue(commands.LF);
    return this;
};

/**
 * 打印文字并换行
 * @param  {string}  content  文字内容
 */
printerJobs.prototype.println = function (content = '') {
    return this.print(content + commands.EOL);
};

/**
 * 设置对齐方式
 * @param {string} align 对齐方式 LT/CT/RT
 */
printerJobs.prototype.setAlign = function (align) {
    this._enqueue(commands.TEXT_FORMAT['TXT_ALIGN_' + align.toUpperCase()]);
    return this;
};

/**
 * 设置字体
 * @param  {string} family A/B/C
 */
printerJobs.prototype.setFont = function (family) {
    this._enqueue(commands.TEXT_FORMAT['TXT_FONT_' + family.toUpperCase()]);
    return this;
};

/**
 * 设定字体尺寸
 * @param  {number} width 字体宽度 1~2
 * @param  {number} height 字体高度 1~2
 */
printerJobs.prototype.setSize = function (width, height) {
    if (2 >= width && 2 >= height) {
        this._enqueue(commands.TEXT_FORMAT.TXT_NORMAL);
        if (2 === width && 2 === height) {
            this._enqueue(commands.TEXT_FORMAT.TXT_4SQUARE);
        } else if (1 === width && 2 === height) {
            this._enqueue(commands.TEXT_FORMAT.TXT_2HEIGHT);
        } else if (2 === width && 1 === height) {
            this._enqueue(commands.TEXT_FORMAT.TXT_2WIDTH);
        }
    }
    return this;
};

/**                                                                                                   if (typeof bold !== 'boolean') {
    bold = true;
  }                                                                                                    
  this._enqueue(bold ? commands.TEXT_FORMAT.TXT_BOLD_ON : commands.TEXT_FORMAT.TXT_BOLD_OFF);
  return this;
};

/**
 * 设定是否开启下划线                                                 * @param  {boolean} underline
 */
printerJobs.prototype.setUnderline = function (underline) {
    if (typeof underline !== 'boolean') {
        underline = true;
    }
    this._enqueue(underline ? commands.TEXT_FORMAT.TXT_UNDERL_ON : commands.TEXT_FORMAT.TXT_UNDERL_OFF);
    return this;
};

/**
 * 设置行间距为 n 点行,默认值行间距是 30 点
 * @param {number} n 0≤n≤255
 */
printerJobs.prototype.setLineSpacing = function (n) {
    if (n === undefined || n === null) {
        this._enqueue(commands.LINE_SPACING.LS_DEFAULT);
    } else {
        this._enqueue(commands.LINE_SPACING.LS_SET);
        this._enqueue([n]);
    }
    return this;
};

/**
 * 打印空行
 * @param {number} n
 */
printerJobs.prototype.lineFeed = function (n = 1) {
    return this.print(new Array(n).fill(commands.EOL).join(''));
};

/**
 * 设置放大倍数
 * @param x 0-7 字符宽放大倍数
 * @param y 0-7 字符高放大倍数
 */
printerJobs.prototype.setCharacterMultiple = function (x, y) {
    this._enqueue([0x1d, 0x21]);
    if (0 <= x && x <= 7 && 0 <= y && y <= 7) {
        var cmd = x * 16 + y;
        this._enqueue([cmd]);
    }
    return this;
};

/**
 *  * 打印二维码
 * @param content 条码数据
 * @param barcodeType 条码类型：
 * 0：PDF417， 1：DATAMATRIX ， 2：QRCODE。
 * @param param1，param2，param3  条码参数：
 * 三个参数表示不同的意思：
 * 1. PDF417
 * param1：表示每行字符数，1<=n<=30。
 * param2：表示纠错等级，0<=n<=8。
 * param3：表示纵向放大倍数。
 * 2. DATAMATRIX
 * param1：表示图形高，0<=n<=144(0:自动选择)。
 * param2：表示图形宽，8<=n<=144(param1 为 0时,无效)。
 * param3：表示纵向放大倍数。
 * 3. QRCODE
 * param1：表示图形版本号，1<=n<=30(0:自动选择)。
 * param2：表示纠错等级，n = 76,77,81,72(L:7%,M:15%,Q:25%,H:30%)。
 * param3：表示纵向放大倍数。
 *
 */
printerJobs.prototype.printQrcode = function (content, barcodeType, param1, param2, param3) {
    var str = content;
    var length = str.replace(/[^\u0000-\u00ff]/g, "aa").length;
    this._enqueue([0x1d, 0x5a]);
    this._enqueue([barcodeType]);
    this._enqueue([0x1b, 0x5a]);
    this._enqueue([param1]);
    this._enqueue([param2]);
    this._enqueue([param3]);
    this._enqueue([length % 256]);
    this._enqueue([length / 256]);
    this.print(content);
    return this;
};

printerJobs.prototype.queryStatus = function () {
    this._enqueue([0x10, 0x04, 0x02]);
    return this;
};

printerJobs.prototype.printimg = function (imageInfo = {}) {
    let arr = imageInfo.array,
        width = imageInfo.width,
        height = imageInfo.height;
    const writeArray = [];
    const xl = width % 256;
    const xh = width / 256;
    const hl = height % 256;
    const hh = height / 256;
    //分行发送图片数据,用的十进制指令
    const command = [29, 118, 48, 0, xl, xh, hl, hh];
    // for (let i = 0; i < arr.length / width; i++) {
    //     const subArr = arr.slice(i * width, i * width + width);
    //     const tempArr = command.concat(subArr);
    //     writeArray.push(new Uint8Array(tempArr));
    // }
    const tempArr = command.concat(arr);
    writeArray.push(new Uint8Array(tempArr));
    let encoded = Array.from(writeArray);
    this._enqueue(encoded);
    return this;
}

/**
 * 清空任务
 */
printerJobs.prototype.clear = function () {
    this._queue = Array.from(commands.HARDWARE.HW_INIT);
    return this;
};

/**
 * 返回ArrayBuffer
 */
printerJobs.prototype.buffer = function () {
    return new Uint8Array(this._queue).buffer;
};


/**
 * CPCL打印
 */

/**
 * 设置标签宽高 必须在开头设置
 * width:80mm 为576；58mm为384
 */
printerJobs.prototype.label_set_page = function (width, height) {
    var content = "! 0 200 200 " + height + " 1\r\nPAGE-WIDTH " + width + "\r\n";
    this.text(content);
    console.log(content);
    return this;
};

/**
 * 打印表格
 * lineWidth:边框线条宽度0-1
 * top_left_x:左上角X坐标
 * top_left_y:左上角Y坐标
 * bottom_right_x:右下角X坐标
 * bottom_right_y:右下角y坐标
 */
printerJobs.prototype.drawbox = function (lineWidth, top_left_x, top_left_y, bottom_right_x, bottom_right_y) {
    var content = "BOX " + top_left_x + " " + top_left_y + " " + bottom_right_x + " " + bottom_right_y + " " + lineWidth + "\r\n";
    this.text(content);
    console.log(content);
    return this;
};


/**
 *  标签打印 必须在结尾调用
 * @param horizontal 0:正常打印，不旋转；1：整个页面顺时针旋转180°后，打印
 * @param skip       0：打印结束后不定位，直接停止；1：打印结束后定位到标签分割线，如果无缝隙，最大进纸260mm后停止
 */
printerJobs.prototype.label_print = function (horizontal, skip) {
    var horizontal1;
    var str;
    switch (horizontal) {
        case 0:
            horizontal1 = 0;
            break;
        case 1:
            horizontal1 = 1;
            break;
        case 2:
            horizontal1 = 2;
            break;
        default:
            horizontal1 = 0;
    }

    if (skip == 1) {
        str = "PR " + horizontal1 + "\r\nFORM\r\nPRINT\r\n";
    } else {
        str = "PR " + horizontal1 + "\r\nPRINT\r\n";
    }
    this.text(str);
    console.log(str);
    return this;
};

/**
 * 打印一维码
 *    VB       39      1      0                        100 480 100 12345678912345
 * {command} {type} {width} {ratio}宽条与窄条的比率 {height} {x} {y} {data}
 * @param start_x   打印的起始横坐标
 * @param start_y   打印的起始纵坐标
 * @param text      字符串
 * @param barcodeType      条码类型
 *                  0：CODE39；1：CODE128；2：CODE93；3：CODEBAR；4：EAN8；5：EAN13；6：UPCA
 *                  ;7:UPC-E;8:ITF
 * @param rotate    旋转角度 0：不旋转；1 旋转
 * @param linewidth 条码宽度
 * @param height    条码高度
 */
printerJobs.prototype.drawBarCode = function (rotate,barcodeType, linewidth,ratio,height,start_x, start_y, text) {
    var str1 = "B";
    if (rotate == 1) {
        str1 = "VB";
    }
    var st1 = "UPCA";
     if (barcodeType == 3) {
        st1 = "39";
    } else if (barcodeType == 4) {
        st1 = "93";
    } else if (barcodeType == 5) {
        st1 = "128";
    } else if (barcodeType == 6) {
        st1 = "CODABAR";
    } else if (barcodeType == 7) {
        st1 = "UPCA";
    }
    var content = str1 + " " + st1 + " " + linewidth + " " +ratio+" "+ height + " " + start_x + " " + start_y + " " + text + "\r\n";
    this.text(content);
    console.log(content);
    return this;
};

/**
 * 打印二维码
 * @param start_x 二维码起始位置
 * @param start_y 二维码结束位置
 * @param text    二维码内容
 * @param rotate  旋转角度 0：不旋转；1 旋转
 * @param ver     : QrCode宽度(2-15)
 * @param lel     : QrCode纠错等级(0-20)
 */
printerJobs.prototype.drawQrCode = function (start_x, start_y, text, rotate, ver, lel) {
    var str1 = "B";
    if (rotate == 1) {
        str1 = "VB";
    }
    var content = str1 + " QR " + start_x + " " + start_y + " " + " M " + " " + 2 + " " + "U" + " " + ver + " " + "\r\n" + "MA," + text + "\r\n" + "ENDQR" + "\r\n";

    this.text(content);
    console.log(content);
    return this;
};

/**
 * 打印文字
 *
 * @param text_x    起始横坐标
 * @param text_y    起始纵坐标
 * @param text      字符串
 * @param font：    字体名称/编号。 值(1,2,3,4,5,6,7,8,20,55,28)
 * @param size：    字体的大小标识。(默认值 0，最大值 7) 
 * @param rotate    旋转角度 0：不旋转；1：90度；2：180°；3:270°
 * @param bold      是否粗体 0：取消；1：设置
 * @param underline 是有有下划线 false:没有；true：有
 * @param reverse   是否反白 false：不反白；true：反白
 * 

 * 
 * 
 */
printerJobs.prototype.drawText = function (text_x, text_y, text, font,size, rotate, bold, reverse, underline) {
    var st1 = "";
    if (rotate == 0) {
        st1 = "T";
    } else if (rotate == 1) {
        st1 = "T90";
    } else if (rotate == 2) {
        st1 = "T180";
    } else if (rotate == 3) {
        st1 = "T270";
    }
    var rev = 0;
    var und = 0;
    if (reverse) {
        rev = 1;
    }
    if (underline) {
        und = 1;
    }
    var content = "SETBOLD " + bold + "\r\n" + "IT " + rev + "\r\n" + "UT " + und + "\r\n" 
           + st1 + " " + font + " " + size + " " + text_x + " " + text_y + " " + text + "\r\n";

    this.text(content);
    console.log(content);
    return this;
};

/**
 * 打印反显
 */
printerJobs.prototype.inverse = function (var1, var2, var3, var4, width) {
    var str1 = "IL";
    var x0 = var1;
    var y0 = var2;
    var x1 = var3;
    var y1 = var4;
    var w = width;
    if (var1 == var3) {
        x0 = var1;
        y0 = var2;
        x1 = var1 + width;
        y1 = var2;
        w = var4 - var2;
    }
    var content = str1 + " " + x0 + " " + y0 + " " + x1 + " " + y1 + " " + w + "\r\n";

    this.text(content);
    console.log(content);
    return this;
};

/**
 * 线条
 *
 * @param lineWidth 线条宽度
 * @param start_x   线条起始点x坐标
 * @param start_y   线条起始点y坐标
 * @param end_x     线条结束点x坐标
 * @param end_y     线条结束点y坐标
 * @param fullline  true:实线  false:?虚线
 */
printerJobs.prototype.drawLine = function (width, x0, y0, x1, y1) {
    var content = "LINE " + x0 + " " + y0 + " " + x1 + " " + y1 + " " + width + "\r\n";


    this.text(content);
    console.log(content);
    return this;
};

/**
     * 打印图形
     *
     * @param imageInfo = {
     *                  imageData: pix,
                        width: w,
                        height: h,
                        threshold: 190,//阈值
     *        }         图片信息
     * @param start_x   图片起始点x坐标
     * @param start_y   图片起始点y坐标
     */
printerJobs.prototype.drawImage = function (imageInfo = {}, start_x, start_y) {
    let arr = imageInfo.array,
        width = imageInfo.width,
        height = imageInfo.height;

    height = parseInt(height);

    var array = Array.from(arr);
    var bmpStr = ab2hex(array);

    var content = "EG " + width + " " + height + " " + start_x + " " + start_y + " " + bmpStr + "\r\n";

    this.text(content);
    console.log(content);
    return this;
};

// ArrayBuffer转16进度字符串示例
function ab2hex(buffer) {
    const hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        function (bit) {
            return ('00' + bit.toString(16)).slice(-2)
        }
    )
    return hexArr.join('')
}


/**
 * 设置打印机 打印成功返回OK
 * @param index ：0关闭，1打开
 * 在开头调用
 */
printerJobs.prototype.setPrintOk = function (index) {
    var content = "CHECKBILL" + " " + index + "\r\n";
    this.text(content);
    console.log(content);
    return this;
};

module.exports = printerJobs;